<script setup lang="ts">
import type { CalendarDateType, CalendarInstance } from 'element-plus'
import { CircleCheckFilled } from '@element-plus/icons-vue'
import { assign, debounce } from 'lodash-es'
import { addDays, format, isBefore, isEqual } from 'date-fns'
import type { Recordable } from '@neucloud/types-base'
import TheFillForm from './components/TheFillForm.vue'

const calendarRef = ref<CalendarInstance>()
const selectedMonth = ref(new Date())

function selectDate(val: CalendarDateType) {
  if (!calendarRef.value) return
  calendarRef.value.selectDate(val)
}

const selectedDates = ref<string[]>([])
function isSelected(date: string) {
  return selectedDates.value.includes(date)
}

const batchSelectRange = reactive({
  start: '',
  end: '',
})
watch(
  () => batchSelectRange,
  () => {
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    if (!isBatchSelecting.value || !batchSelectRange.start || !batchSelectRange.end) return

    const start = new Date(batchSelectRange.start)
    const end = new Date(batchSelectRange.end)

    let s: Date,
      e: Date
      // eslint-disable-next-line prefer-const
    ;[s, e] = isBefore(start, end) ? [start, end] : [end, start]

    const dates = new Set([s])
    let i = s
    while (!isEqual(i, e) && isBefore(i, e)) {
      i = addDays(i, 1)
      dates.add(i)
    }

    selectedDates.value = [...dates].map((date) => format(date, 'yyyy-MM-dd'))
  },
  { deep: true },
)

const [isBatchSelecting, toggleBatchSelect] = useToggle(false)
watch(isBatchSelecting, (value) => {
  if (!value) assign(batchSelectRange, { start: '', end: '' })
})
function handleDateDblclick(date: string) {
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
  handleFill.cancel()
  toggleBatchSelect(true)
  batchSelectRange.start = date
  batchSelectRange.end = date
}
function handleDateMouseenter(date: string) {
  if (!isBatchSelecting.value) return
  batchSelectRange.end = date
}

// TODO: 待限制仅填报当月
function handleDateClick(date: string) {
  const isBatch = isBatchSelecting.value
  if (isBatch) toggleBatchSelect(false)
  else selectedDates.value = [date]

  // eslint-disable-next-line @typescript-eslint/no-use-before-define
  handleFill(isBatch)
}

const filledDates = reactive<Recordable<Recordable<number>>>({})
function isFilled(date: string) {
  return !!filledDates[date]?.length
}

const [showFillDialog, toggleShowFillDialog] = useToggle(false)
const fillDialogParams = reactive({ isBatch: false, dates: [] as string[] })
const handleFill = debounce((isBatch = false) => {
  const dates = selectedDates.value.slice(0)
  assign(fillDialogParams, { isBatch, dates })
  toggleShowFillDialog(true)
}, 300)
</script>

<template>
  <ElCard class="card is-flex">
    <ElDialog
      v-model="showFillDialog"
      title="填报工时"
      width="80%"
      :append-to-body="true"
      :center="true"
      :destroy-on-close="true"
    >
      <TheFillForm
        v-bind="fillDialogParams"
        :filled-dates="filledDates"
      />
    </ElDialog>

    <ElCalendar
      ref="calendarRef"
      v-model="selectedMonth"
      class="calendar"
    >
      <template #header>
        <span>工时日历</span>
        <div class="actions">
          <ElDatePicker
            v-model="selectedMonth"
            style="width: 160px"
            type="month"
            :clearable="false"
          />
          <ElButtonGroup>
            <ElButton @click="selectDate('prev-month')">
              上一月
            </ElButton>
            <ElButton @click="selectDate('next-month')">
              下一月
            </ElButton>
          </ElButtonGroup>
          <ElButton type="primary">
            提交
          </ElButton>
        </div>
      </template>

      <template #date-cell="{ data }">
        <div
          class="calendar-cell-wrapper"
          :class="[{ 'is-selected': isSelected(data.day) }]"
        >
          <div
            class="calendar-cell"
            @click="handleDateClick(data.day)"
            @dblclick="handleDateDblclick(data.day)"
            @mouseenter="handleDateMouseenter(data.day)"
          >
            <div class="text">
              {{ +data.day.split('-').at(-1) }}

              <div
                v-show="isFilled(data.day)"
                class="status"
                :class="[{ 'is-overtime': isFilled(data.day) }]"
              >
                <ElIcon>
                  <CircleCheckFilled />
                </ElIcon>
              </div>
            </div>
          </div>
        </div>
      </template>
    </ElCalendar>

    <ElAlert
      type="info"
      title="操作方式"
    >
      <p>1. 单击日期后填报</p>
      <p>2. 双击日期后开启批量选择，再次单击日期进行填报</p>
    </ElAlert>
  </ElCard>
</template>

<style lang="scss" scoped>
.card {
  height: 100%;

  .calendar {
    .actions {
      > :not(:first-child) {
        margin-left: 10px;
      }
    }

    /* stylelint-disable-next-line */
    :deep(.el-calendar-table__row) {
      > td:first-child,
      > td:last-child {
        .status {
          color: var(--el-color-success);
        }
      }
    }

    :deep(.prev),
    :deep(.current),
    :deep(.next) {
      position: relative;
      z-index: 1;

      &.is-selected {
        background-color: transparent;
      }
    }

    .calendar-cell-wrapper {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: transparent;

      &.is-selected {
        background-color: var(--el-calendar-selected-bg-color);
      }
    }

    .calendar-cell {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      user-select: none;

      > :not(:first-child) {
        margin-top: 4px;
      }

      .text {
        position: relative;
        font-weight: 700;

        /* stylelint-disable-next-line no-descending-specificity */
        .status {
          position: absolute;
          bottom: -100%;
          left: 50%;
          transform: translate(-50%, 2px);
        }
      }
    }
  }
}
</style>

<route lang="json5">
{
  "meta": {
    "index": 0,
    "title": "工时填报",
  },
}
</route>
